
import { WritableAtom, atom } from 'jotai';
import { MMKV } from 'react-native-mmkv'


// 创建实例
export const storage = new MMKV()

/**
 * 表示一个可以用于设置Atom状态的操作。
 * 可以是新的状态值、RESET标记，或者一个函数，接收之前的状态值并返回新的状态值或RESET标记。
 */
type SetStateActionWithReset<Value> = Value | typeof RESET | ((prev: Value) => Value | typeof RESET);

/**
 * 表示一个特殊的符号常量，用于重置Atom的状态为初始值。
 */
export const RESET = Symbol();

/**
 * 获取缓存
 * @param key 需要取的键名
 * @param initialValue 预期之外的值
 * @returns 
 */
export const getValueInStorage = <Value>(key: string, initialValue: Value) => {
  const type = typeof initialValue;
  switch (type) {
    case 'object':
      const value = storage.getString(key);
      if (!value) return initialValue;
      try {
        return JSON.parse(value);
      } catch (error) {
        console.error(error);
        return initialValue;
      }

    case 'string':
      return storage.getString(key) || initialValue;

    case 'number':
      return storage.getNumber(key) || initialValue;

    case 'boolean':
      return storage.getBoolean(key) || initialValue;

    default:
      return storage.contains(key) ? storage.getString(key) : initialValue;
  }
}



/**
* 创建一个带有存储功能的可写Atom。
*
* @param key 存储键值的字符串。
* @param initialValue Atom的初始值。
* @returns 返回一个带有存储功能的可写Atom。
*/
export function atomWithStorage<Value = undefined>(
  key: string,
  initialValue: Value
): WritableAtom<Value, [SetStateActionWithReset<Value>], void> {
  const baseAtom = atom(initialValue);

  // 当Atom挂载时执行的操作，从存储中获取值并设置到Atom中。
  baseAtom.onMount = setAtom => {
    const value = getValueInStorage<Value>(key, initialValue);
    setAtom(value);
  };

  return atom(
    // 获取Atom的值。
    get => get(baseAtom),
    // 更新Atom的值。
    (get, set, update: SetStateActionWithReset<Value>) => {
      const nextValue =
        typeof update === 'function' ? (update as (prev: Value) => Value | typeof RESET)(get(baseAtom)) : update;
      if (nextValue === RESET) {
        // 如果更新的值是RESET，则将Atom重置为初始值，并从存储中删除对应的键值。
        set(baseAtom, initialValue);
        storage.delete(key);
      } else {
        const type = typeof nextValue;
        switch (type) {
          case 'object':
            // 如果更新的值是对象，则将当前值与更新值合并，并设置到Atom中，并将合并后的值以JSON字符串的形式存储到存储中。
            const newValue = { ...get(baseAtom), ...nextValue };
            set(baseAtom, newValue);
            storage.set(key, JSON.stringify(newValue));
            break;

          case 'boolean':
            // 如果更新的值是布尔值，则直接设置到Atom中，并以布尔值的形式存储到存储中。
            set(baseAtom, nextValue);
            storage.set(key, nextValue as boolean);
            break;

          case 'number':
            // 如果更新的值是数字，则直接设置到Atom中，并以数字的形式存储到存储中。
            set(baseAtom, nextValue);
            storage.set(key, nextValue as number);
            break;

          case 'string':
            // 如果更新的值是字符串，则直接设置到Atom中，并以字符串的形式存储到存储中。
            set(baseAtom, nextValue);
            storage.set(key, nextValue as string);
            break;

          case 'undefined':
            // 如果更新的值是undefined，则将Atom重置为undefined，并从存储中删除对应的键值。
            set(baseAtom, nextValue);
            storage.delete(key);
            break;

          default:
            break;
        }
      }
    }
  );
}



/** 是否登录 */
export const signedInAtom = atomWithStorage<boolean>('signedIn', false);


// 登录token
export const tokenAtom = atomWithStorage<Token>('token', '');

// 用户信息Atom
export const userInfoAtom = atomWithStorage<UserInfo>('userInfo', {});
